#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>

const std::string path_name = ".";//简单定义为当前目录即可
const int proj_id = 0;//随便给一个0
const int default_size = 4096;//要求4096字节的整数倍
const int default_mode = 0666;//设置共享内存的初始权限为0666
//直接将共享内存封装成一个类，对外提供接口
class SHM
{
public:
    SHM(int size = default_size):_size(size)
    {
    }

    //创建共享内存
    bool Create()
    {
        _shmid = shmget(ftok(path_name.c_str(),proj_id),_size,IPC_CREAT | IPC_EXCL | default_mode);
        if(_shmid < 0)
            return false;
        return true;
    }

    //获取共享内存
    bool Get()
    {
        _shmid = shmget(ftok(path_name.c_str(),proj_id),_size,IPC_CREAT | default_mode);
        if(_shmid < 0)
            return false;
        return true;
    }

    //建立映射
    bool Shmat()
    {
        _shm_address = shmat(_shmid,nullptr,0);//给默认值0，默认读写权限
        if((long)_shm_address == -1)
            return false;
        _count = (int*)_shm_address;
        *_count = 0;
        return true;
    }

    //解除映射
    bool Shmdt()
    {
        int ret = shmdt(_shm_address);
        if(ret == -1)
            return false;
        return true;
    }

    //删除共享内存
    void Remove()
    {
        shmctl(_shmid,IPC_RMID,nullptr);//需要当共享内存的引用计数为0时，才能够成功删除
    }



    //进程间通信相关
    
    //写行为
    void Write(const std::string& str)
    {
        if(str.empty())
            return;

        //写满了，就不必再写了
        if(*_count >= _size - 4)
            return;
        
        // std::cout << "client write:" << str << std::endl;
        for(const auto& e : str)
        {
            char* ptr = (char*)_shm_address;
            ptr[_wr_pos++] = e;
            (*_count)++;
            if(*_count >= _size - 4)
                return;
        }
    }

    //读行为
    void Read()
    {
        //如果没有写入数据或目前写入的数据均以读出，那就直接返回
        if((*_count == 0) || (_rd_pos == sizeof(int) + *_count))
            return;
        char* ptr = (char*)_shm_address;
        std::string str;
        int edge = sizeof(int) + *_count;
        while(_rd_pos < edge)
        {
            str += ptr[_rd_pos++];
        }
        std::cout << "server read:" << str << std::endl;
    }
   
    //获取共享内存属性状态
    void Status()
    {
        shmctl(_shmid,IPC_STAT,&_status);
        std::cout << "size of shm: " << _status.shm_segsz << std::endl;
        std::cout << "key of shm: " <<  _status.shm_perm.__key << std::endl;
    }

    ~SHM()
    {}



private:
    int _shmid;//用户级别用以确定共享内存的shmid
    int _size;//共享内存定义为多大
    void* _shm_address;//共享内存地址
    struct shmid_ds _status;
    int _wr_pos = 4;//写位置默认从4开始
    int _rd_pos = 4;//读位置默认从4开始
    int* _count;//共享内存的前四个字节用以储存当前有效数据字节数
};